#include <stdlib.h>
#include "expr.h"
#include "libblogc/list.h"

expr * expr_alloc_boolean(int bool)
{
  expr * expr1;

  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_BOOLEAN;
  expr1->bool_expr_val = bool;

  return expr1;
}

expr * expr_alloc_natural(int num)
{
  expr * expr1;

  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_NATURAL;
  expr1->natural_expr_val = num;

  return expr1;
}


expr * expr_alloc_real(double val)
{
  expr * expr1;

  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_REAL;
  expr1->real_expr_val = val;

  return expr1;
}

/* arglist memory is owned by the expr */
expr * expr_alloc_rkvector(void * arglist)
{
  expr * expr1;
  int cnt;
  void * arg;
  int i;                                     /* loop counter */

  cnt = list_count(arglist);

  /* allocate and initialize rkvector expression */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_RkVECTOR;
  expr1->nelems_expr_rkvector = cnt;
  expr1->ppelems_expr_rkvector = (expr **)
    malloc(cnt * sizeof(*expr1->ppelems_expr_rkvector));

  /* initialize the elements in the rkvector */
  i = 0;
  while((arg = list_delete_front(arglist)))
    expr1->ppelems_expr_rkvector[i++] = (expr *)arg;
  
  list_free(arglist);

  return expr1;
}


/* string memory is owned by the expr */
expr * expr_alloc_string(char * string)
{
  expr * expr1;

  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_STRING;
  expr1->string_expr_val = string;
  
  return expr1;
}

/* ident memory is owned by the expr */
expr * expr_alloc_ident(char * ident)
{
  expr * expr1;

  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_IDENTIFIER;
  expr1->ident_expr_val = ident;

  return expr1;
}


/* the fnname and arglist is owned by the expr */
expr * expr_alloc_fn_call(char * fnname, void * arglist)
{
  expr * expr1;
  int cnt;
  void * arg;
  int i;
  
  cnt = list_count(arglist);

  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_FN_CALL;
  expr1->fnname_expr_fn_call = fnname;
  expr1->nargs_expr_fn_call = cnt;
  
  expr1->ppargs_expr_fn_call = (expr **)
    malloc(cnt * sizeof(*expr1->ppargs_expr_fn_call));
  
  i = 0;
  while((arg = list_delete_front(arglist)))
    expr1->ppargs_expr_fn_call[i++] = (expr *)arg;

  list_free(arglist);
  
  return expr1;
}

/* fnname, arglist and paramlist are owned by expr */
expr * expr_alloc_cpd_call(char * fnname, void *paramlist, void *arglist)
{
  expr * expr1;
  void * param;
  void * arg;
  int i;
  
  /* allocate and initialize */
  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_CPD_CALL;
  expr1->fnname_expr_fn_call = fnname;
  expr1->nparams_expr_cpd_call = list_count(paramlist);
  expr1->nargs_expr_cpd_call = list_count(arglist);

  expr1->ppparms_expr_cpd_call = (expr **)
    malloc(expr1->nparams_expr_cpd_call 
           * sizeof(*expr1->ppparms_expr_cpd_call));

  expr1->ppargs_expr_cpd_call = (expr **)
    malloc(expr1->nargs_expr_cpd_call * sizeof(*expr1->ppargs_expr_cpd_call));
  
  i = 0;
  while((param = list_delete_front(paramlist)))
    expr1->ppparms_expr_cpd_call[i++] = (expr *)paramlist;

  i = 0;
  while((arg = list_delete_front(arglist)))
    expr1->ppargs_expr_cpd_call[i++] = (expr *)arg;

  list_free(paramlist);
  list_free(arglist);
  
  return expr1;
}


/* condition, then, and elseif are owned by expr */
expr * expr_alloc_if(expr * condition, expr * then, expr * elseif)
{
  expr * expr1;

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_IF;
  expr1->condition_expr_if = condition;
  expr1->then_expr_if = then;
  expr1->elseif_expr_if = elseif;
  
  return expr1;
  
}


/* typename and condition are owned by expression */
expr * expr_alloc_seti(char * typename, expr * condition)
{
  expr * expr1;

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_SET_IMP;
  expr1->typename_expr_seti = typename;
  expr1->condition_expr_seti = condition;
  
  return expr1;
}

/* arglist is owned by expr */
expr * expr_alloc_sete(void * arglist)
{
  expr * expr1;
  int    cnt;
  void * pelem;
  int    i;                                  /* loop counter */

  cnt = list_count(arglist);

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_SET_EXP;
  expr1->nelems_expr_sete = cnt;
  expr1->ppelems_expr_sete = (expr **)
    malloc(cnt * sizeof(*expr1->ppelems_expr_sete));
 
  i = 0;
  while((pelem = list_delete_front(arglist)))
    expr1->ppelems_expr_sete[i++] = (expr *)pelem;
  
  list_free(arglist);

  return expr1;
}

/* set is now owned by the new expression */
expr * expr_alloc_setc(expr * set)
{
  expr * expr1;

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_SET_CARD;
  expr1->set_expr_setc = set;

  return expr1;
}

/* rhs is owned by expr */
expr * expr_alloc_dep(int isdeterministic, expr * rhs)
{
  expr * expr1;

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_DEP;
  expr1->is_det_expr_dep = isdeterministic;
  expr1->rhs_expr_dep = rhs;
  
  return expr1;
}

expr * expr_alloc_equal(expr * lhs, expr * rhs)
{
  expr * expr1;

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_EQUAL;
  expr1->lhs_expr_equal = lhs;
  expr1->rhs_expr_equal = rhs;
  
  return expr1;
}
expr * expr_alloc_null(void)
{
  expr * expr1;

  expr1 = (expr *)malloc(sizeof(*expr1));
  expr1->type_expr = EXPR_TYPE_NULL;
  
  return expr1;
}
